package com.duojuhe.coremodule.system.service.impl;

import com.duojuhe.cache.LoginUserTokenCache;
import com.duojuhe.cache.SystemDictCache;
import com.duojuhe.common.annotation.DataScopeFilter;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.constant.DataScopeConstants;
import com.duojuhe.common.enums.SystemEnum;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.common.constant.SystemConstants;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.idgenerator.UUIDUtils;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.common.utils.tree.TreeBaseBean;
import com.duojuhe.common.utils.tree.TreeUtil;
import com.duojuhe.coremodule.system.entity.SystemDept;
import com.duojuhe.coremodule.system.entity.SystemDict;
import com.duojuhe.coremodule.system.entity.SystemRoleDept;
import com.duojuhe.coremodule.system.entity.SystemUser;
import com.duojuhe.coremodule.system.mapper.SystemDeptMapper;
import com.duojuhe.coremodule.system.mapper.SystemRoleDeptMapper;
import com.duojuhe.coremodule.system.mapper.SystemUserMapper;
import com.duojuhe.coremodule.system.pojo.dto.dept.*;
import com.duojuhe.coremodule.system.pojo.dto.user.QuerySelectSystemDeptAndUserRes;
import com.duojuhe.coremodule.system.pojo.dto.user.QuerySelectSystemUserReq;
import com.duojuhe.coremodule.system.service.SystemDeptService;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 系统部门相关接口
 */
@Slf4j
@Service
public class SystemDeptServiceImpl extends BaseService implements SystemDeptService {
    @Resource
    private LoginUserTokenCache loginUserTokenCache;
    @Resource
    private SystemDictCache systemDictCache;
    @Resource
    private SystemDeptMapper systemDeptMapper;
    @Resource
    private SystemRoleDeptMapper systemRoleDeptMapper;
    @Resource
    private SystemUserMapper systemUserMapper;

    /**
     *【下拉选择使用-查询部门】查询可供前端选择使用的部门，一般用于添加下拉选择使用
     * @param req
     * @return
     */
    @DataScopeFilter(dataScope = DataScopeConstants.TENANT_ALL_DATA)
    @Override
    public ServiceResult<List<SelectSystemDeptRes>> queryNormalSelectSystemDeptResList(SelectSystemDeptReq req) {
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,deptId desc");
        List<SelectSystemDeptRes> deptList = systemDeptMapper.querySelectSystemDeptResList(req);
        return ServiceResult.ok(deptList);
    }

    /**
     * 根据部门ID获取部门资源信息
     */
    @Override
    public ServiceResult<QuerySystemDeptRes> querySystemDeptResByDeptId(SystemDeptIdReq req) {
        String deptId = req.getDeptId();
        QuerySystemDeptRes res = systemDeptMapper.querySystemDeptResByDeptId(deptId);
        if (res == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        return ServiceResult.ok(res);
    }

    /**
     * 【部门管理-tree型结构查询】查询部门列表，一般用于部门管理界面
     */
    @Override
    @DataScopeFilter
    public ServiceResult<List<QuerySystemDeptTreeRes>> querySystemDeptTreeResList(QuerySystemDeptTreeReq req) {
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,deptId desc");
        List<QuerySystemDeptTreeRes> deptList = systemDeptMapper.querySystemDeptTreeResList(req);
        deptList.forEach(this::setHandleSystemDeptDictNameColor);
        List<TreeBaseBean> tList = TreeUtil.treeList(deptList);
        return ServiceResult.ok(tList);
    }


    @Override
    @DataScopeFilter(dataScope = DataScopeConstants.TENANT_ALL_DATA)
    public ServiceResult<QuerySelectSystemDeptAndUserRes> querySelectSystemDeptAndUserResList(SelectSystemDeptAndUserReq req) {
        //当前登录用户
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前租户简称
        String tenantAbbreviation = userTokenInfoVo.getTenantAbbreviation();
        //构建查询条件
        QuerySelectSystemUserReq userReq = new QuerySelectSystemUserReq();
        userReq.setRealName(req.getKeyword());
        userReq.setCreateDeptId(req.getParentId());
        userReq.setDataScopeFilter(req.getDataScopeFilter());
        PageHelperUtil.defaultOrderBy("createTime desc, userId desc");
        List<SystemUser> systemUserList = systemUserMapper.querySelectMyAllSystemUserList(userReq);
        PageHelper.clearPage();

        SelectSystemDeptReq deptReq = new SelectSystemDeptReq();
        deptReq.setDeptName(req.getKeyword());
        deptReq.setParentId(req.getParentId());
        deptReq.setDataScopeFilter(req.getDataScopeFilter());
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,deptId desc");
        List<SelectSystemDeptRes> deptList = systemDeptMapper.querySelectSystemDeptResList(deptReq);
        PageHelper.clearPage();
        //构建返回值
        QuerySelectSystemDeptAndUserRes res = new QuerySelectSystemDeptAndUserRes();
        res.setEmployees(systemUserList);
        res.setChildDepartments(deptList);
        res.setTitleDepartments(buildTitleDepartments(req.getParentId(),tenantAbbreviation));
        return ServiceResult.ok(res);
    }


    /**
     * 【下拉选择使用-tree型结构查询】一般用于部门下拉选择界面使用
     */
    @Override
    @DataScopeFilter(dataScope = DataScopeConstants.TENANT_ALL_DATA)
    public ServiceResult<List<SelectSystemDeptTreeRes>> queryNormalSelectSystemDeptTreeResList(SelectSystemDeptTreeReq req) {
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,deptId desc");
        List<SelectSystemDeptTreeRes> deptList = systemDeptMapper.queryNormalSelectSystemDeptTreeResList(req);
        List<TreeBaseBean> tList = TreeUtil.treeList(deptList);
        return ServiceResult.ok(tList);
    }

    /**
     * 新增部门信息
     * @param req
     * @return
     */
    @Override
    public ServiceResult saveSystemDept(SaveSystemDeptReq req) {
        //部门ID
        String deptId = UUIDUtils.getUUID32();
        //当前登录用户
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //获取父级部门对象
        BuildParentSystemDeptReq buildParentSystemDept = buildParentSystemDeptByParentId(req.getParentId(),deptId,userTokenInfoVo);
        //部门层级路径
        String deptPath = buildParentSystemDept.getDeptPath();
        //部门父级ID
        String parentId = buildParentSystemDept.getParentId();
        //租户id
        String tenantId = buildParentSystemDept.getTenantId();
        //检查部门名称
        checkSystemDeptName(req.getDeptName(),tenantId);
        //创建归属部门，如果是一级部门的时候默认创建部门ID是自身
        String createDeptId = SystemConstants.UNKNOWN_ID.equals(parentId)?deptId:parentId;
        //当前时间
        Date date = new Date();
        SystemDept systemDept = new SystemDept();
        systemDept.setDeptId(deptId);
        systemDept.setDeptName(req.getDeptName());
        systemDept.setDeptCode(UUIDUtils.getSequenceNo());
        systemDept.setDeptLeader(req.getDeptLeader());
        systemDept.setParentId(parentId);
        systemDept.setDeptPath(deptPath);
        systemDept.setCreateTime(date);
        systemDept.setUpdateTime(date);
        systemDept.setSort(req.getSort());
        systemDept.setRemark(req.getRemark());
        systemDept.setDeptTelephone(req.getDeptTelephone());
        systemDept.setDeptFax(req.getDeptFax());
        systemDept.setCreateUserId(userTokenInfoVo.getUserId());
        systemDept.setUpdateUserId(userTokenInfoVo.getUserId());
        systemDept.setCreateDeptId(createDeptId);
        systemDept.setTenantId(tenantId);
        systemDept.setBuiltIn(SystemEnum.YES_NO.NO.getKey());
        systemDeptMapper.insertSelective(systemDept);
        return ServiceResult.ok(deptId);
    }

    /**
     * 修改部门信息
     * @param req
     * @return
     */
    @Override
    public ServiceResult updateSystemDept(UpdateSystemDeptReq req) {
        SystemDept systemDept = systemDeptMapper.selectByPrimaryKey(req.getDeptId());
        if (systemDept == null) {
            throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
        }
        //部门ID
        String deptId = systemDept.getDeptId();
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //获取父级部门对象
        BuildParentSystemDeptReq buildParentSystemDept = buildParentSystemDeptByParentId(req.getParentId(),deptId,userTokenInfoVo);
        //部门层级路径
        String deptPath = buildParentSystemDept.getDeptPath();
        //部门父级ID
        String parentId = buildParentSystemDept.getParentId();
        //租户id
        String tenantId = buildParentSystemDept.getTenantId();
        //检查部门名称是不是自己
        if (!systemDept.getDeptName().equals(req.getDeptName())){
            //检查部门名称
            checkSystemDeptName(req.getDeptName(),tenantId);
        }
        //检查父级ID是不是自己
        if (systemDept.getDeptId().equals(parentId)) {
            throw new DuoJuHeException(ErrorCodes.PARENT_DEPT_NOT_SELF);
        }
        //检查父级ID是不是自己的下级
        if (!StringUtils.equals(SystemConstants.UNKNOWN_ID, parentId)) {
            if (!SystemEnum.YES_NO.NO.getKey().equals(systemDept.getBuiltIn())){
                throw new DuoJuHeException(ErrorCodes.BUILT_IN_DEPT_NOT_UPDATE_PARENT);
            }
            if (checkChildren(parentId, systemDept.getDeptId())) {
                throw new DuoJuHeException(ErrorCodes.PARENT_DEPT_NOT_SELF_CHILDREN);
            }
        }
        //创建归属部门，如果是一级部门的时候默认创建部门ID是自身
        String createDeptId = SystemConstants.UNKNOWN_ID.equals(parentId)?deptId:parentId;
        //当前时间
        Date date = new Date();
        systemDept.setDeptLeader(req.getDeptLeader());
        systemDept.setParentId(parentId);
        systemDept.setDeptPath(deptPath);
        systemDept.setRemark(req.getRemark());
        systemDept.setDeptTelephone(req.getDeptTelephone());
        systemDept.setDeptFax(req.getDeptFax());
        systemDept.setDeptName(req.getDeptName());
        systemDept.setUpdateTime(date);
        systemDept.setSort(req.getSort());
        systemDept.setUpdateUserId(userTokenInfoVo.getUserId());
        systemDept.setCreateDeptId(createDeptId);
        systemDept.setTenantId(tenantId);
        systemDeptMapper.updateByPrimaryKeySelective(systemDept);
        //部门信息改变了，强制踢出所有该部门的所有在线会话
        loginUserTokenCache.kickOutOnlineUserByDeptId(deptId);
        return ServiceResult.ok(req.getDeptId());
    }

    /**
     * 删除部门
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult deleteSystemDeptByDeptId(SystemDeptIdReq req) {
        String deptId = req.getDeptId();
        SystemDept systemDeptOld = systemDeptMapper.selectByPrimaryKey(deptId);
        if (systemDeptOld == null) {
            throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
        }
        if (!SystemEnum.YES_NO.NO.getKey().equals(systemDeptOld.getBuiltIn())){
            throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
        }
        //检查是否存在子项部门信息
        deleteCheckSystemDeptChildren(deptId);
        //部门存在关联用户禁止删除
        checkSystemUserChildrenByDeptId(deptId);
        //删除该部门之前的所有关联的角色关系
        SystemRoleDept roleDept = new SystemRoleDept();
        roleDept.setDeptId(deptId);
        systemRoleDeptMapper.delete(roleDept);
        //部门删除
        systemDeptMapper.deleteByPrimaryKey(deptId);
        return ServiceResult.ok(deptId);
    }

    /**
     * 获取父级
     * @param parentId
     * @return
     */
    private BuildParentSystemDeptReq buildParentSystemDeptByParentId(String parentId, String deptId, UserTokenInfoVo userTokenInfoVo){
        BuildParentSystemDeptReq buildParentSystemDeptReq = new BuildParentSystemDeptReq();
        //默认为顶级部门，用-1标识
        if (!StringUtils.equals(SystemConstants.UNKNOWN_ID, parentId) && StringUtils.isNotBlank(parentId)) {
            SystemDept parentDept = systemDeptMapper.selectByPrimaryKey(parentId);
            if (parentDept == null) {
                throw new DuoJuHeException(ErrorCodes.PARENT_PARAM_ERROR);
            }
            buildParentSystemDeptReq.setDeptPath(parentDept.getDeptPath() + "/" + deptId);
            buildParentSystemDeptReq.setParentId(parentDept.getDeptId());
            buildParentSystemDeptReq.setTenantId(parentDept.getTenantId());
        }else{
            buildParentSystemDeptReq.setDeptPath("/" + deptId);
            buildParentSystemDeptReq.setParentId(SystemConstants.UNKNOWN_ID);
            buildParentSystemDeptReq.setTenantId(userTokenInfoVo.getTenantId());
        }
        return buildParentSystemDeptReq;
    }


    /**
     * 【私有方法，辅助其他接口方法使用】 查找该节点下面是否存在子节点
     */
    private void deleteCheckSystemDeptChildren(String parentId) {
        if (StringUtils.isBlank(parentId)){
            throw new DuoJuHeException(ErrorCodes.EXIST_CHILDREN_DEPT_NOT_DELETE);
        }
        Example example = new Example(SystemDept.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("parentId", parentId);
        if (systemDeptMapper.selectByExample(example).size() > 0) {
            throw new DuoJuHeException(ErrorCodes.EXIST_CHILDREN_DEPT_NOT_DELETE);
        }
    }

    /**
     * 构建标题部门节点
     * @param parentId
     * @param tenantAbbreviation
     * @return
     */
    private List<SelectSystemDeptRes> buildTitleDepartments(String parentId,String tenantAbbreviation){
        List<SelectSystemDeptRes> titleDepartments = new ArrayList<>();
        SelectSystemDeptRes rootDept = new SelectSystemDeptRes();
        rootDept.setDeptId(SystemConstants.UNKNOWN_ID);
        rootDept.setDeptName(tenantAbbreviation);
        titleDepartments.add(rootDept);
        if (!SystemConstants.UNKNOWN_ID.equals(parentId)&&StringUtils.isNotBlank(parentId)){
            SystemDept systemDept = systemDeptMapper.selectByPrimaryKey(parentId);
            if (systemDept!=null&&StringUtils.isNotBlank(systemDept.getDeptPath())){
                List<String> deptIdList = Arrays.stream(systemDept.getDeptPath().split("/")).filter(string -> !string.isEmpty()).collect(Collectors.toList());
                for (String deptId:deptIdList){
                    SystemDept dept = systemDeptMapper.selectByPrimaryKey(deptId);
                    if (dept==null){
                        continue;
                    }
                    SelectSystemDeptRes deptRes = new SelectSystemDeptRes();
                    deptRes.setDeptId(dept.getDeptId());
                    deptRes.setDeptName(dept.getDeptName());
                    titleDepartments.add(deptRes);
                }
            }
        }
        return titleDepartments;
    }

    /**
     * 【私有方法，辅助其他接口方法使用】 查找该节点下面是否存在子节点
     */
    private void checkSystemUserChildrenByDeptId(String deptId) {
        Example example = new Example(SystemUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("createDeptId", deptId);
        if (systemUserMapper.selectByExample(example).size() > 0) {
            throw new DuoJuHeException(ErrorCodes.DEPT_RELATION_USER_NOT_DELETE);
        }
    }

    /**
     * 【私有方法，辅助其他接口方法使用】 查询菜单code编码是否已经存在
     */
    private void checkSystemDeptName(String deptName,String tenantId) {
        if (StringUtils.isBlank(deptName)||StringUtils.isBlank(tenantId)){
            throw new DuoJuHeException(ErrorCodes.DEPT_NAME_EXIST);
        }
        Example example = new Example(SystemDept.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("deptName", deptName);
        criteria.andEqualTo("tenantId", tenantId);
        if(systemDeptMapper.selectByExample(example).size()>0){
            throw new DuoJuHeException(ErrorCodes.DEPT_NAME_EXIST);
        }
    }

    /**
     * 【私有方法，辅助其他接口方法使用】 检测所选项是不是当前id的子项
     */
    private boolean checkChildren(String deptId, String parentId) {
        if (StringUtils.isBlank(deptId)){
            return true;
        }
        SystemDept dept = systemDeptMapper.selectByPrimaryKey(deptId);
        if (dept==null){
            return true;
        }
        String newPid = dept.getParentId();
        if (newPid.equals(parentId)) {
            return true;
        } else {
            if (!StringUtils.equals(newPid, SystemConstants.UNKNOWN_ID)
                    && !StringUtils.equals(newPid, parentId)) {
                checkChildren(parentId, newPid);
            }
        }
        return false;
    }


    /**
     * 处理返回值的数据字典
     * @param res
     */
    private void setHandleSystemDeptDictNameColor(QuerySystemDeptTreeRes res) {
        if (res==null){
            return;
        }
        SystemDict dictBuiltIn = systemDictCache.getSystemDictByDictCode(res.getBuiltIn());
        res.setBuiltInName(dictBuiltIn.getDictName());
        res.setBuiltInColor(dictBuiltIn.getDictColor());
    }
}
